package client_server;

import static client.ClientApplication.clientBinding;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.StringTokenizer;

import utils.Constants;
import client.ClientApplication;
import client.ClientBindObject;
import client.ClientSocketConnection;
import client_commands.Command;
import client_commands.CommandExecutor;
import client_commands.SET_SERVER_INFOCommand;
import client_gui_chat.ChatDialog;
import client_tree.User;


/**
 * Klaas predstavlja thread koji procesira zahteve pristigle na serverkom procesu klijenta.
 * 
 * U trenutnoj implementaciji, kao zahtevi, mogu se javiti samo dve poruke:
 * 1. SET_SERVER_INFO
 * 2. CLIENT_INIT.
 * 
 * Prva poruka predstavlja odgovor od strane RLM servera na multicast poruku.
 * 
 * Druga poruka predstavlja zahtev od strane drugog RLM klijenta, koji zeli da ostvar
 * P2P konekciju sa ovim klijentom.
 * 
 * @author UrosKrkic & Radivoje Popovic
 */
public class ClientServerProcessing extends Thread implements Constants {

	/**
	 * Referenca na objekat aplikacije.
	 */
	private ClientApplication theApp = null;
	
	
	/**
	 * Socket konekcije.
	 */
	private Socket connectionSocket = null;
	
	
	
	/**
	 * Konstruktor.
	 * @param theApp - referenca na objekat aplikacije
	 * @param connectionSocket - socket
	 * @author UrosKrkic & Radivoje Popovic
	 */
	public ClientServerProcessing(ClientApplication theApp, Socket connectionSocket) {
		this.theApp = theApp;
		this.connectionSocket = connectionSocket;
		
		this.start();
	}
	
	
	
	@Override
	public void run() {
		
		try {
			ClientApplication.callRequestSemaphore.acquire();
		} catch (InterruptedException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
		
		try {
			
			BufferedReader connectionReader = new BufferedReader( new InputStreamReader(connectionSocket.getInputStream()));
			
			String request = connectionReader.readLine();
			
			System.out.println(request);
			
			if ( request.startsWith("SET_SERVER_INFO") && ClientApplication.multicastReceived == false ) {
				ClientApplication.multicastReceived = true;
				
				StringTokenizer tokens = new StringTokenizer(request, " ");
				tokens.nextToken();
				
				Command command = new SET_SERVER_INFOCommand(tokens.nextToken());
				new CommandExecutor(theApp, command);
				
				connectionReader.close();
				connectionSocket.close();
				
				ClientApplication.callRequestSemaphore.release();
				return;
			}
			
			
			if( !request.startsWith("CLIENT_INIT")) {
				connectionSocket.close();
				ClientApplication.callRequestSemaphore.release();
				return;
			}
			
			try {
				ClientApplication.dialogSemaphore.acquire();
			}
			catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			
			String username = parseRequest(request);
			
			ClientSocketConnection newConnection = new ClientSocketConnection(theApp, connectionSocket, P2P_CONNECTION);
			
			newConnection.setUsername(username);				
			
			newConnection.writeData( "CLIENT_ID " + Long.toString( newConnection.getConnectionID() ) );				
			
			
			try {
				ClientApplication.bindingSemaphore.acquire();
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			ClientBindObject cbo = clientBinding.get(username);
			
			User user = theApp.getClientModel().getOnlineModel().getUserByUsername(username);
			
			if (user == null) {
				user = theApp.getClientModel().getOfflineModel().getUserByUsername(username);
			}
			
			if ( cbo != null ) {
				if ( cbo.getConnection() != null ) {
					if ( cbo.getConnection().getConnectionID() > newConnection.getConnectionID() ) {
						cbo.setConnection(newConnection);
						if (cbo.isDialogOpen() == true) {
							cbo.getDialog().setConnection(newConnection);
						}
						else {
							ChatDialog dialog = new ChatDialog(theApp.getWindow(), user);
							cbo.setChatDialog(dialog);
							cbo.setChatDialogConnection(cbo.getConnection());
							dialog.setVisible(true);
						}
					}
				}
				else {
					cbo.setConnection(newConnection);
					cbo.setChatDialogConnection(newConnection);
					cbo.getDialog().setSendButtonRights(true);
				}
			}
			else {
				cbo = new ClientBindObject(user, newConnection);
				clientBinding.put(username, cbo);
				
				ChatDialog dialog = null;
				
				if (cbo.isDialogOpen() == false) {
					dialog = new ChatDialog(theApp.getWindow(), user);
					cbo.setChatDialog(dialog);
					cbo.setChatDialogConnection(cbo.getConnection());
					dialog.setVisible(true);
				}
				else {
					dialog = cbo.getDialog();
					cbo.setChatDialog(dialog);
					cbo.setChatDialogConnection(cbo.getConnection());
				}
			}
			
			ClientApplication.bindingSemaphore.release();
			ClientApplication.dialogSemaphore.release();
			ClientApplication.callRequestSemaphore.release();
		}
		catch (IOException ioe) {
			ioe.printStackTrace();
			ClientApplication.callRequestSemaphore.release();
		}
	}
	
	
	
	/**
	 * Parsira prvu poruku nakon uspostavljanja konekcije i vraca
	 * korisnicko ime klijenta koji je inicirao.
	 * @param request - zahtev
	 * @return - korisnicko ime
	 * @author UrosKrkic & Radivoje Popovic
	 */
	private String parseRequest(String request) {
		StringTokenizer tokenizer = new StringTokenizer(request);
		tokenizer.nextToken();
		
		return tokenizer.nextToken();
	}
	
}
